package com.ruoyi.system.modbus;

import com.alibaba.fastjson2.JSON;
import com.ruoyi.system.domain.EqPool;
import com.ruoyi.system.service.IEqPoolService;
import com.ruoyi.system.service.InitService;
import com.ruoyi.system.socket.ReturunSocket;
import com.ruoyi.system.socket.WebSocketServer;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.code.DataType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;

@Component("modbusTask")
public class ModbusManager {
    @Autowired
    private IEqPoolService eqPoolService;

    private static ModbusManager manager;
    private static ModbusMaster masterA;
    private static ModbusMaster masterB;
    private static ModbusMaster masterAA;
    private static ModbusMaster masterBB;
    private static boolean isSD = false;
    @Autowired
    private InitService initService;

    @PostConstruct
    public void init() {
        //开启ModbusTcpMaster连接
        ModbusTcpMaster modbusTcpMasterA = new ModbusTcpMaster();
        masterA = modbusTcpMasterA.getSlave("192.168.0.117", 500);
        masterA.setTimeout(500);
        ModbusTcpMaster modbusTcpMasterB = new ModbusTcpMaster();
        masterB = modbusTcpMasterB.getSlave("192.168.0.118", 500);
        masterB.setTimeout(500);
        ModbusTcpMaster modbusTcpMasterAA = new ModbusTcpMaster();
        masterAA = modbusTcpMasterAA.getSlave("192.168.0.117", 502);
        masterAA.setTimeout(500);
        ModbusTcpMaster modbusTcpMasterBB = new ModbusTcpMaster();
        masterBB = modbusTcpMasterBB.getSlave("192.168.0.118", 502);
        masterBB.setTimeout(500);
    }

    public static ModbusManager newInstance() {
        if (manager == null || masterA == null || masterB == null) {
            manager = new ModbusManager();
        }
        return manager;
    }

    public static void main(String[] args) {
        ModbusManager.newInstance().init();
        ModbusManager.newInstance().modbusQuartz();
    }

    public void test() {
        //2.1	控制单个继电器   站号、写入地址-输出点（0）、开关    （功能码05）
        //打开站号为1输出点为1的继电器
        boolean t01 = ModbusController.writeCoil(masterB, 1, 0, true);
        //关闭站号为1输出点为1的继电器
        boolean t02 = ModbusController.writeCoil(masterB, 1, 0, false);

        //批量写入(0x)  控制多个继电器
        //站号为1输出点为1 2 3的继电器 修改状态为   打开  关闭  打开  （功能码0F）
        boolean t03 = ModbusController.writeCoils(masterB, 1, 0, new boolean[]{true, false, true});

        //获取继电器状态
        boolean t04 = ModbusController.readCoilStatus(masterB, 1, 0, "test");

        //获取继电器状态
        //模拟量接液位传感器，获取液位高度，液位的高度与模拟量的数值  控制通道数值offset获取指定数据
        Number t05 = ModbusController.readInputRegisters(masterA, 1, 0, DataType.TWO_BYTE_INT_UNSIGNED, "test");
        System.out.println("t05:" + t05);
    }

    /**
     * 定时任务执行方法
     */
    public void modbusQuartz() {

        // initService.printTime();

        try {
            System.out.println("执行modbus定时任务");
            //继电器
//        Boolean[] a1 = getValveDevice("a1");
//        Boolean[] a2 = getValveDevice("a2");
//        Boolean[] b1 = getValveDevice("b1");
//        Boolean[] b2 = getValveDevice("b2");
//        Boolean[] b3 = getValveDevice("b3");
//        //水泵状态
//        boolean e1 = getWaterPumpDeviceStatus("e1");
//        boolean e2 = getWaterPumpDeviceStatus("e2");
//        boolean e3 = getWaterPumpDeviceStatus("e3");
//        boolean e4 = getWaterPumpDeviceStatus("e4");
//        //液位计
//        Number a11 = getLevelGaugeNum("a1");
//        Number a22 = getLevelGaugeNum("a2");
//        Number b11 = getLevelGaugeNum("b1");
//        Number b22 = getLevelGaugeNum("b2");
//        Number b33 = getLevelGaugeNum("b3");
//        //浮球开关
//        Boolean floaterStatus = getFloaterStatus();

            if (isSD) {
                Thread.sleep(300);
                isSD = false;
            }
            //实时存储数据库
            //水池    继电器与液位计
            updatePoolSql("a1");
            updatePoolSql("a2");
            updatePoolSql("b1");
            updatePoolSql("b2");
            updatePoolSql("b3");
            //水泵
            updateWaterPumpSql("e1");
            updateWaterPumpSql("e2");
            updateWaterPumpSql("e3");
            updateWaterPumpSql("e4");
            //浮球开关
            updateFloaterSql("d1");
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    private void updatePoolSql(String tag) {
        //继电器
        Boolean[] a1 = getValveDevice(tag);
        //液位计
        Number a11 = getLevelGaugeNum(tag);
        a11 = "a2".equals(tag) ? a11.intValue() - (1760 - 780) : a11;

        int offset = 820;
        double i1 = Math.abs(Math.max(a11.intValue(), offset) - offset);
        double d = i1 / (1850f - offset) * 33.5;//数值转换为厘米
        //
        d = d == 0 ? d : d + 2;
        //
        EqPool eqPool1 = new EqPool();
        eqPool1.setB3(tag);
        EqPool eqPool = eqPoolService.selectEqPoolB3(tag);
        if (eqPool != null) {
            eqPool.setInletValve(a1[0] ? 1 : 2);
            eqPool.setOutletValve(a1[1] ? 1 : 2);
            eqPool.setCurrentAltitude(new BigDecimal(d));//液位计
            eqPoolService.updateEqPool(eqPool);
        }
        System.out.println("执行modbus定时任务---继电器-液位计" + tag + "-->" + a1 + "----" + a11 + "--------" + d);
    }

    private void updateWaterPumpSql(String tag) {
        //水泵状态
        boolean e1 = getWaterPumpDeviceStatus(tag);
        EqPool eqPool1 = new EqPool();
        eqPool1.setB3(tag);
        EqPool eqPool = eqPoolService.selectEqPoolB3(tag);
        if (eqPool != null) {
            eqPool.setPumpStatus(e1 ? 1 : 2);
            eqPoolService.updateEqPool(eqPool);
        }
        System.out.println("执行modbus定时任务---水泵状态" + tag + "-->" + e1 + "-->" + eqPool.getPumpStatus());
    }

    private void updateFloaterSql(String tag) {
        //浮球开关
        Boolean floaterStatus = getFloaterStatus();
        EqPool eqPool1 = new EqPool();
        eqPool1.setB3(tag);
        EqPool eqPool = eqPoolService.selectEqPoolB3(tag);
        if (eqPool != null) {
            eqPool.setBallStatus(floaterStatus ? 1 : 2);
            eqPoolService.updateEqPool(eqPool);
        }
        System.out.println("执行modbus定时任务---浮球开关" + tag + "-->" + floaterStatus);
    }

    /**
     * todo
     * 关闭所有
     * 1开  2关闭  0忽略
     */
    public boolean closeAll() {
        boolean b = ModbusController.writeCoils(masterBB, 1, 0,
                new boolean[]{false, false, false, false, false, false, false, false, false, false});
        boolean b1 = ModbusController.writeCoils(masterAA, 1, 0,
                new boolean[]{false, false, false, false});
        return b | b1;
    }

    /**
     * todo
     * 控制沉淀池与衰变池阀门状态  a1 a2 b1 b2 b3   应急池c1只有一个入口阀门
     * 1开  2关闭  0忽略
     *
     * @param tag
     * @param inValveStatus
     * @param outValveStatus
     */
    public boolean controlValveDevice(String tag, int inValveStatus, int outValveStatus) {
        isSD = true;
        int inWriteOffset = -1;
        int outWriteOffset = -1;
        switch (tag) {
            case "a1":
                inWriteOffset = 8;
                outWriteOffset = 0;
                break;
            case "a2":
                inWriteOffset = 9;
                outWriteOffset = 1;
                break;
            case "b1":
                inWriteOffset = 2;
                outWriteOffset = 5;
                break;
            case "b2":
                inWriteOffset = 3;
                outWriteOffset = 6;
                break;
            case "b3":
                inWriteOffset = 4;
                outWriteOffset = 7;
                break;
        }
        if (inValveStatus != 0) {
            Boolean inStatus = ModbusController.writeCoil(masterBB, 1, inWriteOffset, inValveStatus == 1 ? true : false);
        }
        if (outValveStatus != 0) {
            Boolean outStatus = ModbusController.writeCoil(masterBB, 1, outWriteOffset, outValveStatus == 1 ? true : false);
        }
        return true;
    }

    /**
     * 控制4个水泵开关 e1  e2 e3 e4
     * <p>
     * * 1开  2关闭  0忽略
     *
     * @param tag
     * @param status
     */
    public boolean controlWaterPumpDevice(String tag, int status) {
        isSD = true;
        int writeOffset = -1;
        switch (tag) {
            case "e1":
                writeOffset = 0;
                break;
            case "e2":
                writeOffset = 1;
                break;
            case "e3":
                writeOffset = 2;
                break;
            case "e4":
                writeOffset = 3;
                break;
        }
        if (status != 0) {
            Boolean inStatus = ModbusController.writeCoil(masterAA, 1, writeOffset, status == 1 ? true : false);
        }
        return true;
    }

    /**
     * 获取继电器状态
     *
     * @param tag 水池数据库标号
     */
    public Boolean[] getValveDevice(String tag) {
        int inWriteOffset = -1;
        int outWriteOffset = -1;
        switch (tag) {
            case "a1":
                inWriteOffset = 8;
                outWriteOffset = 0;
                break;
            case "a2":
                inWriteOffset = 9;
                outWriteOffset = 1;
                break;
            case "b1":
                inWriteOffset = 2;
                outWriteOffset = 5;
                break;
            case "b2":
                inWriteOffset = 3;
                outWriteOffset = 6;
                break;
            case "b3":
                inWriteOffset = 4;
                outWriteOffset = 7;
                break;
        }
        //获取继电器状态
        boolean in = ModbusController.readCoilStatus(masterB, 1, inWriteOffset, "test");
        boolean out = ModbusController.readCoilStatus(masterB, 1, outWriteOffset, "test");
        return new Boolean[]{in, out};
    }

    /**
     * 获取水泵状态
     *
     * @param tag 水池数据库标号
     */
    public boolean getWaterPumpDeviceStatus(String tag) {
        int writeOffset = -1;
        switch (tag) {
            case "e1":
                writeOffset = 0;
                break;
            case "e2":
                writeOffset = 1;
                break;
            case "e3":
                writeOffset = 2;
                break;
            case "e4":
                writeOffset = 3;
                break;
        }
        boolean status = ModbusController.readCoilStatus(masterA, 1, writeOffset, "test");
        return status;
    }

    /**
     * 获取液位计高度
     *
     * @param tag
     */
    public Number getLevelGaugeNum(String tag) {
        int writeOffset = -1;
        switch (tag) {
            case "a1":
                writeOffset = 0;
                break;
            case "a2":
                writeOffset = 1;
                break;
            case "b1":
                writeOffset = 2;
                break;
            case "b2":
                writeOffset = 3;
                break;
            case "b3":
                writeOffset = 4;
                break;
        }
        Number number = ModbusController.readInputRegisters(masterA, 1, writeOffset, DataType.TWO_BYTE_INT_UNSIGNED, "test");
        return number;
    }

    /**
     * 获取浮球开关
     */
    public Boolean getFloaterStatus() {
        boolean status = ModbusController.readInputStatus(masterA, 1, 0, "test");
        return !status;
    }


}
